package moonlit.chill.pay.service.impl.ali;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import lombok.extern.slf4j.Slf4j;
import moonlit.chill.pay.cache.PayConfigDataCache;
import moonlit.chill.pay.constants.Constants;
import moonlit.chill.pay.constants.PayType;
import moonlit.chill.pay.service.PayStrategy;
import moonlit.chill.pay.util.AliPayClientUtil;
import moonlit.chill.pay.vo.PayConfig;
import moonlit.chill.pay.vo.PayResult;
import moonlit.chill.pay.vo.PayResultForNotify;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * @author MoonlitChill
 * @date 2024/4/15 16:41
 */
@Slf4j
@Service("aliNotifyStrategy")
public class AliNotifyStrategyServiceImpl implements PayStrategy {

    @Resource
    private PayConfigDataCache payConfigDataCache;

    @Autowired
    private AliPayClientUtil aliPayClientUtil;

    private static final String CALL_BACK_SUCCESS = "success";

    private static final String TRADE_FINISHED = "TRADE_FINISHED";

    private static final String TRADE_SUCCESS = "TRADE_SUCCESS";

    @Override
    public PayResult<String> payForNotify(HttpServletRequest request, HttpServletResponse response) {
        PayResult<String> result = new PayResult<>();
        Map<String, String[]> aliParams = request.getParameterMap();
        Map<String, String> conversionParams = new HashMap<>();
        for (String key : aliParams.keySet()) {
            String[] values = aliParams.get(key);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            // 乱码解决，这段代码在出现乱码时使用。如果mySign和sign不相等也可以使用这段代码转化
            // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");
            conversionParams.put(key, valueStr);
        }
        log.info(String.format("支付宝异步回调返回数据:%s", JSONUtil.toJsonStr(conversionParams)));
        result.setDataForCallback(CALL_BACK_SUCCESS);
        try {
            PayConfig payConfig = payConfigDataCache.getPayConfig();
            boolean signVerified;
            if (payConfig.getAliType() == 0){
                //证书模式
                String aliPayPublicKey = aliPayClientUtil.getAliPayCertPath(payConfig);
                signVerified = AlipaySignature.rsaCertCheckV1(conversionParams, aliPayPublicKey, "utf-8", "RSA2");
            } else {
                //密钥模式
                String aliPayPublicKey = payConfig.getPublicKey();
                signVerified = AlipaySignature.rsaCheckV1(conversionParams, aliPayPublicKey, "utf-8", "RSA2");
            }
            log.info("支付宝异步回调验签结果:" + signVerified);
            if (signVerified) {
                this.check(conversionParams, result);
                //验签通过 获取交易状态
                String tradeStatus = conversionParams.get("trade_status");
                if (result.isSuccess() && tradeStatus.equals(TRADE_SUCCESS)) {
                    if (StrUtil.isNotEmpty(conversionParams.get("out_biz_no"))) {
                        result.error("支付宝异步回调非支付", Constants.PAY_FAIL_CODE);
                        result.setDataForCallback(CALL_BACK_SUCCESS);
                        return result;
                    }
                    PayResultForNotify payResultForNotify = new PayResultForNotify();
                    payResultForNotify.setPayType(PayType.ALI);
                    payResultForNotify.setTransNum(conversionParams.get("out_trade_no"));
                    payResultForNotify.setPayAmount(new BigDecimal(conversionParams.get("receipt_amount")));
                    payResultForNotify.setOutTradeNo(conversionParams.get("trade_no"));
                    payResultForNotify.setPayTime(conversionParams.get("gmt_payment"));
                    payResultForNotify.setBody(conversionParams.get("body"));
                    result.setSuccess(Boolean.TRUE);
                    result.setResult(JSONUtil.toJsonStr(payResultForNotify));
                }
                if (tradeStatus.equals(TRADE_FINISHED)) {
                    result.error("支付宝异步回调 状态为TRADE_FINISHED", Constants.PAY_FAIL_CODE);
                }
            } else {
                result.error("支付宝异步回调验签失败", Constants.PAY_FAIL_CODE);
            }
        } catch (AlipayApiException e) {
            result.errorWithException(e.getErrMsg(), Constants.PAY_ERROR_CODE, e);
            result.setDataForCallback(CALL_BACK_SUCCESS);
        }
        return result;
    }

    private void check(Map<String, String> conversionParams, PayResult<?> result) {
        PayConfig payConfig = payConfigDataCache.getPayConfig();
        //1 校验通知中的seller_id（或者seller_email)是否为out_trade_no这笔单据的对应的操作方
        if (!conversionParams.get("seller_id").equals(payConfig.getUId())) {
            result.error("收款方id不匹配", Constants.PAY_FAIL_CODE);
        }
        //2验证app_id是否为该商户本身。
        if (!conversionParams.get("app_id").equals(payConfig.getAppId())) {
            result.error("商户appId不匹配", Constants.PAY_FAIL_CODE);
        }
    }

}
